﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Dwarf.Managed
{
    /// <summary>
    /// Solve the Combinational Logic problem with Serial parallelization.
    /// </summary>
    /// <remarks> 
    /// For the demonstration purposes of the project, 
    /// we have chosen the algorithm that counts the number of “1” bits in a bit string.
    /// </remarks>
    class Solver
    {
        /// <summary>
        /// Reference to file.
        /// </summary>
        public BinaryReader input;

        /// <summary>
        /// Length of file
        /// </summary>
        public int length;

        /// <summary>
        /// Result counter
        /// </summary>
        public ulong resultCount = 0;

        /// <summary>
        /// Empty constructor.
        /// </summary>
        public Solver()
        {
        }

        /// <summary>
        /// Serial based method.
        /// </summary>
        public void Solve()
        {            
            //Temp counter
            ulong count = 0;

            //Loop while not End Of File.
            while (length - (int)input.BaseStream.Position >= 8) 
            {
                //Read block of data from file.                
                ulong temp = input.ReadUInt64();

                //This line of code is used for decrease of input file size.
                //Such modification would reduce the input file size, 
                //but the algorithm is still belongs dwarf.
                //Also this line does not affect the result.
                for (int k = 0; k < 1000000; k++)
                {
                    count = temp;

                    //Calculate number of “1” in current uint64.
                    count -= (count >> 1) & 0x5555555555555555;
                    count = (count & 0x3333333333333333) + ((count >> 2) & 0x3333333333333333);
                    count = (count + (count >> 4)) & 0x0f0f0f0f0f0f0f0f;                    
                }

                resultCount += count * 0x0101010101010101 >> 56;
            }

            count = 0;

            byte len = (byte)(length - (int)input.BaseStream.Position);

            for (byte i = 0; i < len; i++) 
            {
                count += (ulong)(input.ReadByte() << i * 8); 
            }

            count -= (count >> 1) & 0x5555555555555555;
            count = (count & 0x3333333333333333) + ((count >> 2) & 0x3333333333333333);
            count = (count + (count >> 4)) & 0x0f0f0f0f0f0f0f0f;

            resultCount += count * 0x0101010101010101 >> 56;
        }

    }
}
